<!-- ! 超级表格 -->
<template>
  <div class="tablePro">
    <!-- 搜索 -->
    <SearchForm
      v-show="isShowSearch"
      :search="search"
      :reset="reset"
      :columns="searchColumns"
      :search-param="searchParam"
      :search-col="searchCol"
    />
    <!-- 主体 -->
    <div class="table-main card">
      <!-- 表格头部 操作按钮 -->
      <div class="table-header">
        <div class="header-button-lf">
          <slot
            name="tableHeader"
            :selected-list-ids="selectedListIds"
            :selected-list="selectedList"
            :is-selected="isSelected"
          ></slot>
        </div>
        <div v-if="toolButton" class="header-button-ri">
          <slot name="toolButton">
            <el-button :icon="Refresh" circle @click="getTableList" />

            <el-button
              v-if="columns.length"
              :icon="Operation"
              circle
              @click="openColSetting"
            />
            <el-button
              v-if="searchColumns.length"
              :icon="Search"
              circle
              @click="isShowSearch = !isShowSearch"
            />
          </slot>
        </div>
      </div>
      <!-- 表格显示 -->
      <el-table
        class="tableRef"
        ref="tableRef"
        v-bind="$attrs"
        :data="data ?? tableData"
        :border="border"
        :row-key="rowKey"
        @selection-change="selectionChange"
      >
        <template v-for="(item, index) in tableColumns" :key="index">
          <el-table-column
            v-if="
              item?.tableItem?.type &&
              ['selection', 'index', 'expand'].includes(item?.tableItem?.type)
            "
            label="#"
            v-bind="item.tableItem"
            :align="item?.tableItem?.align ?? 'center'"
          >
          </el-table-column>
          <el-table-column
            v-else-if="
              item?.prop &&
              item?.tableItem?.isShow !== false &&
              !item.tableItem?.type
            "
            v-bind="item.tableItem"
            :align="item?.tableItem?.align ?? 'center'"
            :label="item.label"
            :prop="item.prop"
          >
            <!-- 内容插槽 -->
            <template #default="{ row }">
              <slot :name="handleProp(item.prop)" :row="row">
                <component
                  :is="renderCellData(item, row)"
                  v-if="item?.tableItem?.render"
                ></component>

                <template v-else>
                  {{ renderCellData(item, row) }}
                </template>
              </slot>
            </template>

            <!-- 列标题插槽 -->
            <template #header="{ row }">
              <slot :name="`${handleProp(item.prop)}Header`" :row="row">
                <component
                  v-if="item?.tableItem?.headerRender"
                  :is="item?.tableItem?.headerRender?.(row)"
                ></component>

                <template v-else>
                  {{ item.label }}
                </template>
              </slot>
            </template>
          </el-table-column>
        </template>
        <!-- 插入表格最后一行之后的插槽 -->
        <template #append>
          <slot name="append"> </slot>
        </template>
        <!-- 无数据 -->
        <template #empty>
          <div class="table-empty">
            <slot name="empty">
              <img src="@/assets/images/notData.png" alt="notData" />
              <div>暂无数据</div>
            </slot>
          </div>
        </template>
      </el-table>

      <!-- 分页组件 -->
      <slot name="pagination">
        <Pagination
          v-if="pagination"
          :pageable="pageable"
          :handle-size-change="handleSizeChange"
          :handle-current-change="handleCurrentChange"
        />
      </slot>
    </div>

    <!-- 列设置 -->
    <ColSetting
      v-if="toolButton"
      ref="colRef"
      v-model:col-setting="colSetting"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, watch, computed, provide, onMounted } from "vue";
import { ElTable } from "element-plus";
import SearchForm from "@/components/SearchForm/index.vue";
import Pagination from "@/components/Pagination/index.vue";
import ColSetting from "./components/ColSetting.vue";
import { Refresh, Operation, Search } from "@element-plus/icons-vue";
import type { TableProType } from "./interface/";
// import { useTable } from "./useTable";
import { handleRowAccordingToProp, handleProp } from "./helper";

// 接受父组件参数，配置默认值
const props = withDefaults(defineProps<TableProType.Props>(), {
  columns: () => [],
  requestAuto: true,
  pagination: true,
  initParam: {},
  border: true,
  toolButton: true,
  rowKey: "id",
  searchCol: () => ({ xs: 1, sm: 2, md: 2, lg: 3, xl: 4 }),
});
// 是否显示搜索模块
const isShowSearch = ref(true);

// 表格 DOM 元素
const tableRef = ref<InstanceType<typeof ElTable>>();

// 表格多选 Hooks
const { selectionChange, selectedList, selectedListIds, isSelected } =
  useSelection(props.rowKey);

// 表格操作 Hooks
const {
  tableData,
  pageable,
  searchParam,
  searchInitParam,
  getTableList,
  search,
  reset,
  handleSizeChange,
  handleCurrentChange,
} = useTable(
  props.requestApi,
  props.initParam,
  props.pagination,
  props.dataCallback,
  props.requestError
);

// 清空选中数据列表
const clearSelection = () => tableRef.value!.clearSelection();

// 渲染表格数据，可做【定制】的数据渲染
const renderCellData = (item: ColumnsProps, v: any) => {
  // h 函数
  if (typeof item.tableItem?.render === "function")
    return item.tableItem.render(v);

  // 默认数据
  return handleRowAccordingToProp(v, item.prop!);
};

// 初始化请求
onMounted(() => props.requestAuto && getTableList());

// 监听页面 initParam 改化，重新获取表格数据
watch(() => props.initParam, getTableList, { deep: true });

// 接收 columns 并设置为响应式
const tableColumns = ref<ColumnsProps[]>(props.columns);

// 列设置 ==> 过滤掉不需要设置的列
const colRef = ref();
const colSetting = tableColumns.value!.filter((item) => {
  if (item?.tableItem?.isShow !== false) {
    item.tableItem.isShow = true;
  }
  return (
    !["selection", "index", "expand"].includes(item.tableItem.type!) &&
    item.prop !== "operation"
  );
});
const openColSetting = () => colRef.value.openColSetting();

// 过滤需要搜索的配置项
const searchColumns = props.columns.filter((item) => item.searchItem);

// 暴露给父组件的参数和方法(外部需要什么，都可以从这里暴露出去)
defineExpose({
  element: tableRef,
  tableData,
  pageable,
  searchParam,
  searchInitParam,
  getTableList,
  search,
  reset,
  handleSizeChange,
  handleCurrentChange,
  clearSelection,
  isSelected,
  selectedList,
  selectedListIds,
});
</script>

<style scoped lang="less">
@import "./index.less";
</style>
